package org.example.mygobang.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.example.mygobang.game.MatchRequest;
import org.example.mygobang.game.MatchResponse;
import org.example.mygobang.game.Matcher;
import org.example.mygobang.game.OnlineUserManager;
import org.example.mygobang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.File;

@Component
public class MatchAPI extends TextWebSocketHandler {
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private OnlineUserManager onlineUserManager;
    @Autowired
    private Matcher matcher;
    //连接成功后需要执行的方法
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("连接成功");
        //当连接成功后，我希望有一个容器，里面装的是所有在线用户的信息
        //我们使用 OnlineUserManager 类中的 ConcurrentHashMap<Integer, WebSocketSession> 容器来实现
        //这里只要有用户上线，我们就进行添加
        try {
            //这里需要注意的是，如果我们跳过了登录页面直接访问游戏大厅，那么这里的user可能为null，
            //所以我们这里的处理是，如果为null，进行访问时，就会出现空指针异常，然后我在catch中进行处理后，返回前端
            //使前端跳回登录页面
            User user = (User) session.getAttributes().get("user");
            //然后我们还得解决的问题是，当前用户是否已经在线，如果在线那么我们将不再允许该账号登录
            //让前端跳回登录页面，也就是解决多开问题
            System.out.println("userId:" + user.getUserId() + " " + user.getUsername());
            if(onlineUserManager.getFromGameHall(user.getUserId()) != null
                    || onlineUserManager.getFromGameRoom(user.getUserId()) != null) {
                //如果不为空，则说明存在多开问题，那么我们就构造 多开问题的MatchResponse进行返回
                MatchResponse matchResponse = new MatchResponse();
                //该账号是登录成功的，只是存在多开问题
                matchResponse.setOk(true);
                //错误信息打印
                matchResponse.setReason("当前禁止多开");
                //表示这是一个多开状态
                matchResponse.setMessage("repeatConnection");
                //转换我们所需要的数据格式（JSON字符串）进行返回
                session.sendMessage(new TextMessage(objectMapper.writeValueAsString(matchResponse)));
                return;
            }
            //拿到了身份信息之后, 就可以把玩家设置成在线状态了
            onlineUserManager.enterGameHall(user.getUserId(), session);
            System.out.println("玩家 " + user.getUsername() + " 进入游戏大厅!");
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionEstablished] 当前用户未登录!");
            // e.printStackTrace();
            // 出现空指针异常, 说明当前用户的身份信息是空, 用户未登录呢.
            // 把当前用户尚未登录这个信息给返回回去~~
            MatchResponse response = new MatchResponse();
            response.setOk(false);
            response.setReason("您尚未登录! 不能进行后续匹配功能!");
            session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response)));
        }
    }
    //收到消息后需要执行的方法
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 实现处理开始匹配请求和处理停止匹配请求
        User user = (User) session.getAttributes().get("user");
        // 获取到客户端给服务器发送的数据
        String payload = message.getPayload();
        // 由于当前这个数据载荷是一个 JSON 格式的字符串，就需要把它转成我们提前构造好的 MatchRequest
        MatchRequest request = objectMapper.readValue(payload,MatchRequest.class);
        MatchResponse response = new MatchResponse();
        //启动匹配
        if(request.getMessage().equals("startMatch")) {
            //启动匹配后，我们希望有一个匹配队列或者容器来放正在匹配的玩家信息
            //这里，专门用一个类来表示：Matcher
            //该类里面提供两个方法，添加与删除，供调用；

            // 把玩家信息放入匹配队列之后，就可以返回哟个响应给客户端
            matcher.add(user);
            // 构造 response
            response.setOk(true);
            response.setMessage("startMatch");
        } else if(request.getMessage().equals("stopMatch")) {
            //退出队列
            matcher.remove(user);
            // 构造 response
            response.setOk(true);
            response.setMessage("stopMatch");
        } else if(request.getMessage().equals("historical")) {
            File file = new File(user.getUsername());
            if(file.exists()) {

            }

        } else {
            // 除此之外可能也存在非法请求，这里也进行处理一下
            response.setOk(true);
            response.setMessage("非法匹配请求");
        }
        // 返回响应数据
        String jsonstring = objectMapper.writeValueAsString(response);
        session.sendMessage(new TextMessage(jsonstring));
    }
    //连接异常时需要执行的方法
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        try {
            // 玩家下线，我们首先删除在线玩家
            User user = (User) session.getAttributes().get("user");
            // 获取下线玩家的 session
            WebSocketSession webSocketSession = onlineUserManager.getFromGameHall(user.getUserId());
            // 防止出现多开现象
            if(webSocketSession == session) {
                onlineUserManager.exitGameHall(user.getUserId());
                // 如果玩家正在匹配中，而 websocket 来凝结断开了，此时就应该移除队列
                matcher.remove(user);
            }
        } catch (NullPointerException e) {
            // 防止出现空指针异常
            System.out.println("当前用户未登录");
        }
    }
    //连接关闭需要执行的方法
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        try {
            // 玩家下线, 从 OnlineUserManager 中删除
            User user = (User) session.getAttributes().get("user");
            WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId());
            if (tmpSession == session) {
                //为了防止多开情况下，第二个玩家退出影响到第一个玩家
                onlineUserManager.exitGameHall(user.getUserId());
                // 如果玩家正在匹配中, 而 websocket 连接断开了, 就应该移除匹配队列
                matcher.remove(user);
            }
        } catch (NullPointerException e) {
            System.out.println("[MatchAPI.afterConnectionClosed] 当前用户未登录!");

        }
    }
}
